=begin pod

=TITLE class IO::Handle

=SUBTITLE Opened file or stream

   class IO::Handle { }

=head1 Methods

=head2 method open

Defined as:

=for code :method
method open(IO::Handle:D:
    :$bin, :$enc, :$chomp, :$nl-in, Str:D :$nl-out,
    Str :$mode,
    :$r, :$w, :$a, :$x, :$update, :$rw, :$rx, :$ra,
    :$create, :$append, :$truncate, :$exclusive,
    :$out-buffer,
    --> IO::Handle:D
)

Opens the handle in one of the modes. L<Fails|/routine/fail> with appropriate
exception if the open fails.

See description of individual methods for the accepted values and behaviour
of L«C<:$chomp>|/type/IO::Handle#method_chomp»,
L«C<:$nl-in>|/type/IO::Handle#method_nl-in»,
L«C<:$nl-out>|/type/IO::Handle#method_nl-out», and
L«C<:$enc>|/type/IO::Handle#method_encoding». The values for parameters default
to the invocant's attributes and if any of them are provided, the attributes will
be updated to the new values. Specify C<:$bin> set to C<True> instead of
C<:$enc> to indicate the handle should be opened in binary mode. Specifying
undefined value as C<:$enc> is equivalent to not specifying C<:$enc> at all.
Specifying both a defined encoding as C<:$enc> and C<:$bin> set to true will
cause C<X::IO::BinaryAndEncoding> exception to be thrown.

The open mode defaults to non-exclusive, read only (same as specifying
C<:r>) and can be controlled by a mix of the following arguments:

=begin code :skip-test :allow< B R >
:r      same as specifying   :mode<ro>

:w      same as specifying   :mode<wo>, :create, :truncate
:a      same as specifying   :mode<wo>, :create, :append
:x      same as specifying   :mode<wo>, :create, :exclusive

:update same as specifying   :mode<rw>
:rw     same as specifying   :mode<rw>, :create
:ra     same as specifying   :mode<rw>, :create, :append
:rx     same as specifying   :mode<rw>, :create, :exclusive
=end code

Support for combinations of modes I<other> than what is listed above
is implementation-dependent and should be assumed unsupported. That is,
specifying, for example, C<.open(:r :create)> or
C<.open(:mode<wo> :append :truncate)> might work or might cause the Universe
to implode, depending on a particular implementation.

The mode details are:

=begin code :skip-test :allow< B R >
:mode<ro>  means "read only"
:mode<wo>  means "write only"
:mode<rw>  means "read and write"

:create    means the file will be created, if it does not exist
:truncate  means the file will be emptied, if it exists
:exclusive means .open will fail if the file already exists
:append    means writes will be done at the end of file's current contents
=end code

Attempts to open a directory, write to a handle opened in read-only mode
or read from a handle opened in write-only mode,
or using text-reading methods on a handle opened in binary mode will
fail or throw.

In B<6.c> language, it's possible to open path C<'-'>, which will cause
C<open> to open (if C<closed>) the C<$*IN> handle if opening in read-only
mode or to open the C<$*OUT> handle if opening in write-only mode. All other
modes in this case will result in exception being thrown.

In B<6.d> language, path C<'-'> has no special meaning.

The C<:out-buffer> controls output buffering and by default behaves as if
it were C<Nil>. See method L<out-buffer> for details.

B<Note:> unlike some other languages, Perl 6 does not use reference counting,
and so B<the file handles are NOT flushed or closed when they go out of scope>.
While they I<will> get closed when garbage collected, garbage collection isn't
guaranteed to get run. This means I<you should> use an explicit C<close> on
handles opened for writing, to avoid data loss, and
an explicit C<close> is I<recommended> on handles opened for reading as well, so
that your program does not open too many files at the same time, triggering
exceptions on further C<open> calls.

=head2 method comb

Defined as:

    method comb(IO::Handle:D: Bool :$close, |args --> Seq:D)

Read the handle and processes its contents the same way
L«C<Str.comb>|/type/Str#routine_comb» does, taking the same arguments, closing
the handle when done if C<$close> is set to a true value. Implementations may
slurp the file in its entirety when this method is called.

Attempting to call this method when the handle is
L<in binary mode|/type/IO::Handle#method_encoding> will result in
C<X::IO::BinaryMode> exception being thrown.

=for code
my $fh = 'path/to/file'.IO.open;
say "The file has {+$fh.comb: '♥', :close} ♥s in it";

=head2 method chomp

Defined as:

    has $.chomp is rw = True

One of the attributes that can be set via C<.new> or L<open>.
Defaults to C<True>. Takes a L<Bool> specifying whether the line separators
(as defined by L«C<.nl-in>|/type/IO::Handle#method_nl-in») should be removed
from content when using L«C<.get>|/type/IO::Handle#method_get» or
L«C<.lines>|/type/IO::Handle#routine_lines» methods.

=head2 routine get

Defined as:

    method get(IO::Handle:D: --> Str:D)
    multi sub get (IO::Handle $fh = $*ARGFILES --> Str:D)

Reads a single line of input from the handle, removing the trailing newline
characters (as set by L«C<.nl-in>|/routine/nl-in»)
if the handle's C<.chomp> attribute is set to C<True>. Returns
C<Nil>, if no more input is available. The subroutine form defaults to
L«C<$*ARGFILES>|/language/variables#index-entry-%24%2AARGFILES» if no handle
is given.

Attempting to call this method when the handle is
L<in binary mode|/type/IO::Handle#method_encoding> will result in
C<X::IO::BinaryMode> exception being thrown.

=begin code
$*IN.get.say;              # Read one line from the standard input

my $fh = open 'filename';
$fh.get.say;               # Read one line from a file
$fh.close;

say get;                   # Read one line from $*ARGFILES
=end code

=head2 routine getc

Defined as:

    method getc(IO::Handle:D: --> Str:D)
    multi sub getc (IO::Handle $fh = $*ARGFILES --> Str:D)

Reads a single character from the input stream. Attempting to call this method
when the handle is L<in binary mode|/type/IO::Handle#method_encoding> will
result in C<X::IO::BinaryMode> exception being thrown. The subroutine form
defaults to L«C<$*ARGFILES>|/language/variables#index-entry-%24%2AARGFILES» if
no handle is given. Returns C<Nil>, if no more input is available, otherwise
operation will block, waiting for at least one character to be available; these
caveats apply:

=head3 Buffering terminals

Using getc to get a single keypress from a terminal will only work properly if
you've set the terminal to "unbuffered". Otherwise the terminal will wait for
the return key to be struck or the buffer to be filled up before perl6 gets
even a single byte of data.

=head3 Waiting for potential combiners

If your handle's encoding allows combining characters to be read, perl6 will
wait for more data to be available before it provides a character. This means
that inputting an "e" followed by a combining acute will give you an e with an
acute rather than giving an "e" and letting the next reading function give you
a dangling combiner. However, it also means that when the user inputs just an
"e" and has no intention to also input a combining acute, your program will be
waiting for another keypress before the initial "e" is returned.

=head2 submethod DESTROY

Defined as:

    submethod DESTROY(IO::Handle:D:)

Closes the filehandle, unless its L<native-descriptor> is C<2> or lower. This
ensures the standard file handles do not get inadvertently closed.

Note that garbage collection is not guaranteed to
happen, so you must NOT rely on C<DESTROY> for closing the handles you
I<write to> and instead close them yourself. Programs that open a lot of files
should close the handles explicitly as well, regardless of whether they were
open for writing, since too many files might get opened before garbage
collection happens and the no longer used handles get closed.

=head2 method gist

Defined as:

    method gist(IO::Handle:D: --> Str:D)

Returns a string containing information which
L«C<.path>|/type/IO::Handle#method_path», if any, the handle is created for
and whether it is L«C<.opened>|/type/IO::Handle#method_opened».

=begin code
say IO::Handle.new; # IO::Handle<(Any)>(closed)
say "foo".IO.open;  # IO::Handle<"foo".IO>(opened)
=end code

=head2 method eof

Defined as:

    method eof(IO::Handle:D: --> Bool:D)

Non-blocking. Returns C<True> if the read operations have exhausted the
contents of the handle. For L<seekable|/routine/seek> handles, this means
current position is at or beyond the end of file and L<seeking|/routine/seek>
an exhausted handle back into the file's contents will result in
L<eof> returning C<False> again.

On L<non-seekable|/routine/seek> handles and handles opened to zero-size
files (including special files in C</proc/>), EOF won't be set
until a read operation fails to read any bytes. For example, in this code,
the first C<read> consumes all of the data, but it's only until the second
C<read> that reads nothing would the EOF on a TTY handle be set:

    =begin code :lang<shell>
    $ echo "x" | perl6 -e 'with $*IN { .read: 10000; .eof.say; .read: 10; .eof.say }'
    False
    True
    =end code

=head2 method encoding

Defined as:

    multi method encoding(IO::Handle:D: --> Str:D)
    multi method encoding(IO::Handle:D: $enc --> Str:D)

Returns a L<Str> representing the encoding currently used by
the handle, defaulting to C<"utf8">. C<Nil> indicates the file handle is
currently in binary mode. Specifying an optional positional C<$enc> argument
switches the encoding used by the handle; specify C<Nil> as encoding to put the
handle into binary mode.

The accepted values for encoding are case-insensitive. The available encodings
vary by implementation and backend. On Rakudo MoarVM the following are
supported:

=for code :skip-test
utf8
utf16
utf8-c8
iso-8859-1
windows-1251
windows-1252
ascii

The default encoding is utf8, which undergoes normalization into Unicode B<NFC>
(normalization form canonical). In some cases you may want to ensure no
normalization is done; for this you can use C<utf8-c8>. Before using C<utf8-c8>
please read L<Unicode: File Handles and I/O|/language/unicode#File_Handles_and_I/O>
for more information on C<utf8-c8> and B<NFC>.

Implementation may choose to also provide support for aliases, e.g. Rakudo
allows aliases C<latin-1> for C<iso-8859-1> encoding and dashed utf versions:
C<utf-8> and C<utf-16>.

=begin code
with 'foo'.IO {
    .spurt: "First line is text, then:\nBinary";
    my $fh will leave {.close} = .open;
    $fh.get.say;         # OUTPUT: «First line is text, then:␤»
    $fh.encoding: Nil;
    $fh.slurp.say;       # OUTPUT: «Buf[uint8]:0x<42 69 6e 61 72 79>␤»
}
=end code

=head2 routine lines

Defined as:

    sub lines(IO::Handle:D $fh = $*ARGFILES, $limit = Inf, :$close --> Seq:D)
    method lines(IO::Handle:D:               $limit = Inf, :$close --> Seq:D)

Return a L<Seq> each element of which is a line from the handle (that is
chunks delineated by L«C<.nl-in>|/type/IO::Handle#method_nl-in»). If the
handle's L«C<.chomp>|/type/IO::Handle#method_chomp» attribute is set to C<True>,
then characters specified by L«C<.nl-in>|/type/IO::Handle#method_nl-in» will be
stripped from each line.

Reads up to C<$limit> lines, where C<$limit> can be a non-negative L<Int>,
C<Inf>, or L<Whatever> (which is interpreted to mean C<Inf>). If C<:$close> is
set to C<True>, will close the handle when the file ends or C<$limit> is
reached. Subroutine form defaults to
L«C<$*ARGFILES>|/language/variables#index-entry-%24%2AARGFILES», if no
handle is provided.

Attempting to call this method when the handle is
L<in binary mode|/type/IO::Handle#method_encoding> will result in
C<X::IO::BinaryMode> exception being thrown.

B<NOTE:> the lines are read lazily, so ensure the returned L<Seq> is either
L<fully reified|/language/glossary#index-entry-Reify> or is no longer needed
when you close the handle or attempt to use any other methods that change the
file position.

=begin code
say "The file contains ",
  '50GB-file'.IO.open.lines.grep(*.contains: 'Perl').elems,
  " lines that mention Perl";
# OUTPUT: «The file contains 72 lines that mention Perl␤»
=end code

=head2 method lock

Defined as:

    method lock(IO::Handle:D: Bool:D :$non-blocking = False, Bool:D :$shared = False --> True)

Places an advisory lock on the filehandle. If C<:$non-blocking> is C<True>
will L«C<fail>|/routine/fail» with C<X::IO::Lock> if lock could not be
obtained, otherwise will block until the lock can be placed. If C<:$shared>
is C<True> will place a shared (read) lock, otherwise will place an
exclusive (write) lock. On success, returns C<True>; L«fails|/routine/fail»
with C<X::IO::Lock> if lock cannot be placed (e.g. when trying to place
a shared lock on a filehandle opened in write mode or trying to
place an exclusive lock on a filehandle opened in read mode).

You can use C<lock> again to replace an existing lock with another one.
To remove a lock, L«C<close>|/routine/close» the filehandle or use
L«C<unlock>|/routine/unlock».

=begin code
# One program writes, the other reads, and thanks to locks either
# will wait for the other to finish before proceeding to read/write

# Writer
given "foo".IO.open(:w) {
    .lock;
    .spurt: "I ♥ Perl 6!";
    .close;
}

# Reader
given "foo".IO.open {
    .lock: :shared;
    .slurp.say; # OUTPUT: «I ♥ Perl 6!␤»
    .close;
}
=end code

=head2 method unlock

Defined as:

    method unlock(IO::Handle:D: --> True)

Removes a L«C<lock>|/routine/lock» from the filehandle.

=head2 routine words

Defined as:

    multi sub words(IO::Handle:D $fh = $*ARGFILES, $limit = Inf, :$close --> Seq:D)
    multi method words(IO::Handle:D: $limit = Inf, :$close --> Seq:D)

Similar to L«C<Str.words>|/type/Str#routine_words», separates the handle's
stream on contiguous chunks of whitespace (as defined
by Unicode) and returns a L<Seq> of the resultant "words." Takes an optional
C<$limit> argument that can be a non-negative L<Int>, C<Inf>, or L<Whatever>
(which is interpreted to mean C<Inf>), to indicate only up-to C<$limit> words
must be returned. If L<Bool> C<:$close> named argument is set to C<True>,
will automatically close the handle when the returned L<Seq> is exhausted.
Subroutine form defaults to
L«C<$*ARGFILES>|/language/variables#index-entry-%24%2AARGFILES», if no handle
is provided.

Attempting to call this method when the handle is
L<in binary mode|/type/IO::Handle#method_encoding> will result in
C<X::IO::BinaryMode> exception being thrown.

=for code
my %dict := bag $*IN.words;
say "Most common words: ", %dict.sort(-*.value).head: 5;

B<NOTE:> implementations may read I<more> data than necessary when a call
to C<.words> is made. That is, C<$handle.words(2)> may read more data than two
"words" worth of data and subsequent calls to read methods might not read from
the place right after the two fetched words. After a call to C<.words>, the
file position should be treated as undefined.

=head2 method split

Defined as:

    method split(IO::Handle:D: :$close, |c)

L<Slurps|/routine/slurp> the handle's content and calls
L«C<Str.split>|/type/Str#routine_split» on it, forwarding any of the given
arguments. If C<:$close> named parameter is set to C<True>, will
L<close> the invocant after slurping.

Attempting to call this method when the handle is L<in binary
mode|/type/IO::Handle#method_encoding> will result in C<X::IO::BinaryMode>
exception being thrown.

=for code
my $fh = 'path/to/file'.IO.open;
$fh.split: '♥', :close; # Returns file content split on ♥

=head2 method spurt

Defined as:

    multi method spurt(IO::Handle:D: Blob $data, :$close = False)
    multi method spurt(IO::Handle:D: Cool $data, :$close = False)

Writes all of the C<$data> into the filehandle, closing it when finished,
if C<$close> is C<True>. For L«C<Cool>|/type/Cool» C<$data>, will use the
encoding the handle is set to use (L«C<IO::Handle.open>|/routine/open»
or L«C<IO::Handle.encoding>|/routine/encoding»).

Behaviour for spurting a L«C<Cool>|/type/Cool» when the handle is in binary
mode or spurting a L«C<Blob>|/type/Blob» when the handle is NOT in binary
mode is undefined.

=head2 method print

Defined as:

    multi method print(**@text --> True)

Writes the given C<@text> to the handle, coercing any non-L<Str> objects
to L<Str> by calling L«C<.Str>|/routine/Str» method on them. See L<write>
to write bytes.

Attempting to call this method when the handle is
L<in binary mode|/type/IO::Handle#method_encoding> will result in
C<X::IO::BinaryMode> exception being thrown.

=for code
my $fh = 'path/to/file'.IO.open: :w;
$fh.print: 'some text';
$fh.close;

=head2 method print-nl

Defined as:

    method print-nl(IO::Handle:D: --> True)

Writes the value of C<$.nl-out> attribute into the handle.

Attempting to call this method when the handle is
L<in binary mode|/type/IO::Handle#method_encoding> will result in
C<X::IO::BinaryMode> exception being thrown.

=for code
my $fh = 'path/to/file'.IO.open: :w, :nl-out("\r\n");
$fh.print: "some text";
$fh.print-nl; # prints \r\n
$fh.close;

=head2 method printf

Defined as:

    method printf(IO::Handle:D: Cool $format, *@args)

Formats a string based on the given format and arguments and C<.print>s the
result into the filehandle.
See L<sub sprintf|https://docs.perl6.org/type/Str#sub_sprintf> for details
on acceptable format directives.

Attempting to call this method when the handle is
L<in binary mode|/type/IO::Handle#method_encoding> will result in
C<X::IO::BinaryMode> exception being thrown.

=for code
my $fh = open 'path/to/file', :w;
$fh.printf: "The value is %d\n", 32;
$fh.close;

=head2 method out-buffer

Defined as:

    method out-buffer(--> Int:D) is rw

Controls output buffering and can be set via an argument to L<open>. Takes
an C<int> as the size of the buffer to use (zero is acceptable). Can take
a L<Bool>: C<True> means to use default, implementation-defined buffer size;
C<False> means to disable buffering (equivalent to using C<0> as buffer size).

Lastly, can take a C<Nil> to enable TTY-based buffering control: if
the handle L<is a TTY|/routine/t>, the buffering is disabled, otherwise,
default, implementation-defined buffer size is used.

See L<flush> to write out data currently in the buffer. Changing buffer
size flushes the filehandle.

=for code
given 'foo'.IO.open: :w, :1000out-buffer {
    .say: 'Hello world!'; # buffered
    .out-buffer = 42;       # buffer resized; previous print flushed
    .say: 'And goodbye';
    .close; # closing the handle flushes the buffer
}


=head2 method put

Defined as:

    multi method put(**@text --> True)

Writes the given C<@text> to the handle, coercing any non-L<Str> objects
to L<Str> by calling L«C<.Str>|/routine/Str» method on them, and appending the
value of L«C<.nl-out>|/type/IO::Handle#method_nl-out» at the end.

Attempting to call this method when the handle is
L<in binary mode|/type/IO::Handle#method_encoding> will result in
C<X::IO::BinaryMode> exception being thrown.

=for code
my $fh = 'path/to/file'.IO.open: :w;
$fh.print: 'some text';
$fh.close;

=head2 method say

Defined as:

    multi method say(IO::Handle:D: **@text --> True)

This method is identical to L<put|/type/IO::Handle#method_put> except
that it stringifies its arguments by calling L«C<.gist>|/routine/gist» instead
of L«C<.Str>|/routine/Str».

Attempting to call this method when the handle is
L<in binary mode|/type/IO::Handle#method_encoding> will result in
C<X::IO::BinaryMode> exception being thrown.

=for code
my $fh = open 'path/to/file', :w;
$fh.say(Complex.new(3, 4));        # RESULT: «3+4i\n»
$fh.close;

=head2 method read

Defined as:

    method read(IO::Handle:D: Int(Cool:D) $bytes = 65536 --> Buf:D)

Binary reading; reads and returns up to C<$bytes> bytes from the filehandle.
C<$bytes> defaults to an implementation-specific value (in Rakudo,
the value of C<$*DEFAULT-READ-ELEMS>, which by default is set to C<65536>).
This method can be called even when the handle is not
L<in binary mode|/type/IO::Handle#method_encoding>.

=begin code
(my $file = 'foo'.IO).spurt: 'I ♥ Perl';
given $file.open {
    say .read: 6; # OUTPUT: «Buf[uint8]:0x<49 20 e2 99 a5 20>␤»
    .close;
}
=end code

=head2 method readchars

Defined as:

    method readchars(IO::Handle:D: Int(Cool:D) $chars = 65536 --> Str:D)

Reading chars; reads and returns up to C<$chars> chars (graphemes) from the
filehandle. C<$chars> defaults to an implementation-specific value (in Rakudo,
the value of C<$*DEFAULT-READ-ELEMS>, which by default is set to C<65536>).
Attempting to call this method when the handle is
L<in binary mode|/type/IO::Handle#method_encoding> will result in
C<X::IO::BinaryMode> exception being thrown.

=begin code
(my $file = 'foo'.IO).spurt: 'I ♥ Perl';
given $file.open {
    say .readchars: 5; # OUTPUT: «I ♥ P␤»
    .close;
}
=end code

=head2 method write

Defined as:

    method write(IO::Handle:D: Blob:D $buf --> True)

Writes C<$buf> to the filehandle. This method can be called even when the
handle is not L<in binary mode|/type/IO::Handle#method_encoding>.

=head2 method seek

Defined as:

     method seek(IO::Handle:D: Int:D $offset, SeekType:D $whence --> True)

Move the file pointer (that is, the position at which any subsequent read
or write operations will begin) to the byte position specified by
C<$offset> relative to the location specified by C<$whence> which may be
one of:

=item SeekFromBeginning

The beginning of the file.

=item SeekFromCurrent

The current position in the file.

=item SeekFromEnd

The end of the file.  Please note that you need to specify a negative
offset if you want to position before the end of the file.

=head2 method tell

Defined as:

    method tell(IO::Handle:D: --> Int:D)

Return the current position of the file pointer in bytes.

=head2 method slurp-rest

Defined as:

    multi method slurp-rest(IO::Handle:D: :$bin! --> Buf)
    multi method slurp-rest(IO::Handle:D: :$enc --> Str)

B<DEPRECATION NOTICE:> this method will be deprecated in C<6.d> language. Do
not use it for new code. Use L«C<.slurp> method|/routine/slurp» method
instead.

Return the remaining content of the file from the current file position
(which may have been set by previous reads or by C<seek>.)  If the
adverb C<:bin> is provided a L<Buf> will be returned,
otherwise the return will be a C<Str> with the optional encoding C<:enc>.

=head2 method slurp

Defined as:

    method slurp(IO::Handle:D: :$close, :$bin)

Returns all the content from the current file position to the end.
If the invocant is in binary mode or if C<$bin> is set to C<True>,
will return a L<Buf>, otherwise will decode
the content using invocant's current L«C<.encoding>|/routine/encoding» and
return a L<Str>.

If C<:$close> is set to C<True>, will close the handle when finished reading.

B<Note:> On L<Rakudo|/language/glossary#Rakudo> this method was introduced
with release 2017.04 and C<$bin> arg was added in 2017.10.

=head2 method Supply

Defined as:

    multi method Supply(IO::Handle:D: :$size = 65536)

Returns a C<Supply> that will emit the contents of the handle in chunks.
The chunks will be L«C<Buf>|/type/Buf» if the handle is in binary mode
or, if it isn't, L«C<Str>|/type/Str» decoded using same encoding as L«C<IO::Handle.encoding>|/routine/encoding».

The size of the chunks is determined by the optional C<:size> named
parameter and C<65536> bytes in binary mode or C<65536> characters in non-binary
mode.

=begin code
"foo".IO.open(:bin).Supply(:size<10>).tap: *.perl.say;
# OUTPUT:
# Buf[uint8].new(73,32,226,153,165,32,80,101,114,108)
# Buf[uint8].new(32,54,33,10)

"foo".IO.open.Supply(:size<10>).tap: *.perl.say;
# OUTPUT:
# "I ♥ Perl 6"
# "!\n"
=end code

=head2 method path

Defined as:

    method path(IO::Handle:D:)

For a handle opened on a file this returns the L<IO::Path> that
represents the file. For the standard I/O handles
L«C<$*IN>|/language/variables#index-entry-%24%2AIN»,
L«C<$*OUT>|/language/variables#index-entry-%24%2AOUT», and
L«C<$*ERR>|/language/variables#index-entry-%24%2AERR» it returns an
L<IO::Special> object.

=head2 method IO

Defined as:

    method IO(IO::Handle:D:)

Alias for L«C<.path>|/type/IO::Handle#method_path»

=head2 method Str

Returns the value of L«C<.path>|/type/IO::Handle#method_path», coerced
to L<Str>.

=for code
say "foo".IO.open.path; # OUTPUT: «"foo".IO␤»

=head2 routine close

Defined as:

    method close(IO::Handle:D: --> Bool:D)
    multi sub close(IO::Handle $fh)

Closes an open file handle. It's not an error to call C<close> on an
already-closed filehandle. Returns C<True> on success. If you close
one of the standard file handles (by default: C<$*IN>, C<$*OUT>, or C<$*ERR>),
that is any handle with L<native-descriptor> C<2> or lower, you won't be
able to re-open such a handle.

It's a common idiom to use L«C<LEAVE> phaser|/language/phasers#LEAVE» for
closing the handles, which ensures the handle is closed regardless of how the
block is left.

=begin code :skip-test
if $do-stuff-with-the-file {
    my $fh = open "path-to-file";
    LEAVE close $fh;
    # ... do stuff with the file
}

sub do-stuff-with-the-file (IO $path-to-file)
  my $fh = $path-to-file.open;

  # stick a `try` on it, since this will get run even when the sub is
  # called with wrong arguments, in which case the `$fh` will be an `Any`
  LEAVE try close $fh;

  # ... do stuff with the file
}

given "foo/bar".IO.open(:w) {
    .spurt: "I ♥ Perl 6!";
    .close;
}
=end code

B<Note:> unlike some other languages, Perl 6 does not use reference counting,
and so B<the file handles are NOT closed when they go out of scope>. While
they I<will> get closed when garbage collected, garbage collection isn't
guaranteed to get run. This means B<you must> use an explicit C<close> on
handles opened for writing, to avoid data loss, and an explicit C<close>
is I<recommended> on handles opened for reading as well, so that your program
does not open too many files at the same time, triggering exceptions on further
C<open> calls.

Note several methods allow for providing C<:close> argument, to close the handle
after the operation invoked by the method completes. As a simpler alternative,
the L<IO::Path> type provides many reading and writing methods that let you work
with files without dealing with file handles directly.

=head2 method flush

Defined as:

    method flush(IO::Handle:D: --> True)

Will flush the handle, writing any of the buffered data. Returns C<True>
on success; otherwise, L<fails|/routine/fail> with C<X::IO::Flush>.

=begin code :skip-test
given "foo".IO.open: :w {
    LEAVE .close;
    $fh.print: 'something';
    'foo'.IO.slurp.say; # (if the data got buffered) OUTPUT: «␤»
    $fh.flush;          # flush the handle
    'foo'.IO.slurp.say; # OUTPUT: «something␤»
}
=end code

=head2 method native-descriptor

Defined as:

    method native-descriptor()

This returns a value that the operating system would understand as a "file descriptor" and
is suitable for passing to a native function that requires a file descriptor as an
argument such as C<fcntl> or C<ioctl>.

=head2 method nl-in

Defined as:

    method nl-in(--> Str:D) is rw

One of the attributes that can be set via C<.new> or L<open>.
Defaults to C<["\x0A", "\r\n"]>.
Takes either a L<Str> or L<Array> of C<Str> specifying input line ending(s) for
this handle. If C<.chomp> attribute is set to C<True>, will strip these endings
in routines that C<chomp>, such as L«C<get>|/routine/get» and
L«C<lines>|/routine/lines».

=begin code
with 'test'.IO {
    .spurt: '1foo2bar3foo'; # write some data into our test file
    my $fh will leave {.close} = .open; # can also set .nl-in via .open arg
    $fh.nl-in = [<foo bar>]; # set two possible line endings to use;
    $fh.lines.say; # OUTPUT: ("1", "2", "3").Seq
}
=end code

=head2 method nl-out

Defined as:

    has Str:D $.nl-out is rw = "\n";

One of the attributes that can be set via C<.new> or L<open>.
Defaults to C<"\n">. Takes a L<Str> specifying output line ending for this
handle, to be used by methods L«C<.put>|/type/IO::Handle#method_put»
and L«C<.say>|/type/IO::Handle#method_say».

=begin code
with 'test'.IO {
    given .open: :w {
        .put: 42;
        .nl-out = 'foo';
        .put: 42;
        .close;
    }
    .slurp.perl.say; # OUTPUT: «"42\n42foo"»
}
=end code

=head2 method opened

Defined as:

    method opened(IO::Handle:D: --> Bool:D)

Returns C<True> if the handle is open, C<False> otherwise.

=head2 method t
X<|tty>

Defined as:

    method t(IO::Handle:D: --> Bool:D)

Returns C<True> if the handle is opened to a
L<TTY|https://en.wikipedia.org/wiki/Terminal_emulator>, C<False> otherwise.

=head1 Related roles and classes

See also the related role L<IO> and the related class L<IO::Path>.

=end pod

# vim: expandtab shiftwidth=4 ft=perl6
